package com.xpj.aspect;

import com.xpj.annotation.CacheEvict;
import com.xpj.template.CacheTemplate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class CacheEvictAspect {

    @Autowired
    private CacheTemplate cacheTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Pointcut("@annotation(com.xpj.annotation.CacheEvict)")
    public void cacheEvictPointcut() {}

    @Around("cacheEvictPointcut() && @annotation(cacheEvict)")
    public Object cacheEvictAround(ProceedingJoinPoint joinPoint, CacheEvict cacheEvict) throws Throwable {

        String cacheKey = CacheAnnotationProcessor.generateCacheKey(joinPoint, cacheEvict);

        if (cacheKey == null){
            log.warn("缓存键生成失败，执行原方法但不清除缓存");
            return joinPoint.proceed();
        }
        // 方法执行后清除缓存
        RLock writeLock = redissonClient.getReadWriteLock("rw:lock:" + cacheKey).writeLock();
        try {
            writeLock.tryLock(3, TimeUnit.SECONDS);
            Object result = joinPoint.proceed();
            cacheTemplate.delete(cacheKey, cacheEvict.delayDelete());
            log.debug("方法执行后清除缓存，key: {}", cacheKey);
            return result;
        }finally {
            if (writeLock.isHeldByCurrentThread()){
                writeLock.unlock();
            }
        }
    }
}
